﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace BigPicWatcher
{
    class GetPhotoInfo
    {
        /// <summary>
        /// 定义图片格式
        /// </summary>
        public enum ImageType
        {
            Null,
            Png,
            Jpg,
            Gif,
            Bmp
        }

        public GetPhotoInfo(Stream stream)
        {
            ImageType itype = getImageType(stream);
            switch (itype)
            { 
                case ImageType.Jpg:
                    ReadJpeg(stream);
                    break;
                case ImageType.Png:
                    ReadPng(stream);
                    break;
                case ImageType.Gif:
                    ReadGif(stream);
                    break;
                case ImageType.Bmp:
                    ReadBmp(stream);
                    break;
            }
        }
        
        public PhotoInfo photoinfo = new PhotoInfo();
        /// <summary>
        /// 获取图片格式
        /// </summary>
        private ImageType getImageType(Stream stream)
        {
            //图片格式
            ImageType type = ImageType.Null;

            //读取图片文件头8个字节，并根据若干个字节来确定图片格式
            byte[] header = new byte[8];
            stream.Read(header, 0, 8);

            //确定图片格式
            if (header[0] == 0x89 &&
                header[1] == 0x50 && // P
                header[2] == 0x4E && // N
                header[3] == 0x47 && // G
                header[4] == 0x0D &&
                header[5] == 0x0A &&
                header[6] == 0x1A &&
                header[7] == 0x0A)
            {
                //Png图片 8字节：89 50 4E 47 0D 0A 1A 0A
                type = ImageType.Png;
            }
            else if (header[0] == 0xFF &&
                    header[1] == 0xD8)
            {
                //Jpg图片 2字节：FF D8
                type = ImageType.Jpg;
            }
            else if (header[0] == 0x47 &&   // G
                    header[1] == 0x49 &&    // I
                    header[2] == 0x46 &&    // F
                    header[3] == 0x38 &&    // 8
                    (header[4] == 0x39 ||   // 9
                    header[4] == 0x37) &&   // 7
                    header[5] == 0x61)      // a
            {
                //Gif图片 6字节：47 49 46 38 39|37 61
                type = ImageType.Gif;
            }
            else if (header[0] == 0x42 &&   //B
                    header[1] == 0x4D)      //M
            {
                //Bmp图片 2字节：42 4D
                type = ImageType.Bmp;
            }
            
            return type;
        }

        private PhotoInfo ReadJpeg(Stream stream)
        {
            stream.Position = 2;
            //段类型
            int type = -1;
            int ff = -1;
            //记录当前读取的位置
            long ps = 0;
            //逐个遍历所以段，查找SOFO段
            do
            {
                do
                {
                    //每个新段的开始标识为oxff，查找下一个新段
                    ff = stream.ReadByte();
                    if (ff < 0) //文件结束
                    {
                        return photoinfo;
                    }
                } while (ff != 0xff);

                do
                {
                    //段与段之间有一个或多个oxff间隔，跳过这些oxff之后的字节为段标识
                    type = stream.ReadByte();
                } while (type == 0xff);

                //记录当前位置
                ps = stream.Position;
                switch (type)
                {
                    case 0x00:
                    case 0x01:
                    case 0xD0:
                    case 0xD1:
                    case 0xD2:
                    case 0xD3:
                    case 0xD4:
                    case 0xD5:
                    case 0xD6:
                    case 0xD7:
                        break;
                    case 0xc0: //SOF0段（图像基本信息）
                    case 0xc2: //JFIF格式的 SOF0段
                        {
                            //找到SOFO段，解析宽度和高度信息
                            getJpgSize(stream);
                            return photoinfo;
                        }
                    default: //别的段都跳过
                        //获取段长度，直接跳过
                        ps = stream.ReadByte() * 256;
                        ps = stream.Position + ps + stream.ReadByte() - 2;
                        break;
                }
                if (ps + 1 >= stream.Length) //文件结束
                {
                    return photoinfo;
                }
                stream.Position = ps; //移动指针
            } while (type != 0xda); // 扫描行开始
            return photoinfo;
        }
        /// <summary>
        /// 解析JPG图片的尺寸
        /// </summary>
        /// <param name="stream"></param>
        private void getJpgSize(Stream stream)
        {
            //跳过2个自己长度信息和1个字节的精度信息
            stream.Seek(3, SeekOrigin.Current);

            //高度 占2字节 低位高位互换
            photoinfo.Height = stream.ReadByte() * 256;
            photoinfo.Height += stream.ReadByte();
            //宽度 占2字节 低位高位互换
            photoinfo.Width = stream.ReadByte() * 256;
            photoinfo.Width += stream.ReadByte();
        }

        private PhotoInfo ReadPng(Stream stream)
        {
            stream.Position = 16;

            //读取宽度，高度 各4字节
            byte[] buffer = new byte[8];
            stream.Read(buffer, 0, buffer.Length);

            Array.Reverse(buffer, 0, 4);
            Array.Reverse(buffer, 4, 4);

            photoinfo.Width = BitConverter.ToInt32(buffer, 0);
            photoinfo.Height = BitConverter.ToInt32(buffer, 4);
            return photoinfo;
        }

        private PhotoInfo ReadGif(Stream stream)
        {
            stream.Position = 6;

            //读取宽度，高度 各2字节
            byte[] buffer = new byte[4];
            stream.Read(buffer, 0, buffer.Length);

            photoinfo.Width = BitConverter.ToInt16(buffer, 0);
            photoinfo.Height = BitConverter.ToInt16(buffer, 2);
            return photoinfo;
        }

        private PhotoInfo ReadBmp(Stream stream)
        {
            stream.Position = 18;
            
            //bmp图片的宽度信息保存在第 18-21位 4字节
            //bmp图片的高度度信息保存在第 22-25位 4字节
            //读取宽度，高度 各4字节
            byte[] buffer = new byte[8];
            stream.Read(buffer, 0, buffer.Length);

            photoinfo.Width = BitConverter.ToInt32(buffer, 0);
            photoinfo.Height = BitConverter.ToInt32(buffer, 4);
            return photoinfo;
        }
    }
    public class PhotoInfo
    {
        /// <summary>
        /// Image dimensions, in pixels.
        /// </summary>
        public int Width, Height;
    }
}
